/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package InternetHax;

import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

/**
 *
 * @author LoginError
 */
public class MapFactory {

    private final static byte COR_NONE = 0;
    private final static byte COR_SCRAMBLE = 1;
    private final static byte COR_EROSION = 2;
    private final static byte COR_ADDITION = 3;
    private final static byte COR_EDGEERODE = 4;
    private final static byte COR_EDGEADD = 5;
    private final static byte MAXROOMS = 10;
    private final static byte NUM_PATHS_TO_RANDOM_ROOM = 3;
    private int yplus = 0,  xplus = 0;
    private int chainfactor = 0;
    private Random generator;
    private int corruptionpercent;
    private int corruptiontype;
    private int x,  y,  v,  w;
    private Map themap;
    private int numrooms;
    private int roomsizex,  roomsizey,  roomsizeTotal;
    private short xsize,  ysize;
    private Vector rooms;
    private AppFactory appFactory;
    
    public MapFactory(AppFactory factory) {
        this.appFactory = factory;
        generator = new Random();
        rooms = new Vector();
    }

    public void makeBlankMap(short xsize, short ysize) {
        this.xsize = xsize;
        this.ysize = ysize;
        themap = new Map(xsize, ysize);

    }
    //quickly makes a map, will never return the same map twice
    public void makeRandomMap(int xsize, int ysize) {

        this.xsize = (short)xsize;
        this.ysize = (short)ysize;
        makeRandomMapFromSeed(System.currentTimeMillis(), COR_NONE, (byte) 0, this.xsize, this.ysize);

    }

    private void makePathBetweenRooms(boolean ignoreWeights, Point2d firstRoom, Point2d otherRoom) {
        Vector path = themap.getPath(ignoreWeights, true, firstRoom, otherRoom);

        if (path == null || path.size() == 0) {
            return;
        }
        for (int i = 0; i < path.size(); i++) {
            Point2d thepoint = (Point2d) path.elementAt(i);
            themap.setTileType(thepoint.x, thepoint.y, Constants.TILE_PATH_DEBUG);
        }

    }
    //DO NOT USE RIGHT NOW!, it breaks everything
    public void mirrorMap(boolean horizontal) {

        for (int j = 0; j < ysize; j++) {
            for (int i = 0; i < xsize / 2; i++) {
                if (horizontal) {
                    themap.setTileType(xsize - i, j, themap.getTileType(i, j));
                }
                else {
                    themap.setTileType(j, ysize - i, themap.getTileType(j, i));
                }
            }
        }

    //return themap;
    }

    public void corruptMap() {
        if (generator.nextInt(100) <= corruptionpercent) {
            switch (corruptiontype) {
                case COR_NONE:
                    break;

                case COR_SCRAMBLE:
                    int chance = generator.nextInt(3);
                    if (chance == 1) {
                        themap.setTileType(x + v, y + w, Constants.TILE_CORRUPTED_SPACE);
                        break;
                    }
                case COR_ADDITION:
                    chainfactor = corruptionpercent;
                    while (chainfactor > 0) {
                        //add a tile next to this one

                        xplus += (generator.nextInt(2) == 1 ? -1 : 1);
                        yplus += (generator.nextInt(2) == 1 ? -1 : 1);
                        themap.setTileType(x + v + xplus, y + w + yplus, Constants.TILE_CORRUPTED_FLOOR);
                        chainfactor -= 5;
                    }
                    break;

                case COR_EROSION:
                    themap.setTileType(x + v, y + w, Constants.TILE_CORRUPTED_SPACE);
                    break;

                case COR_EDGEERODE:
                    if (roomsizex - v == 0 || roomsizey - w == 0 || w == -roomsizex || v == -roomsizey) //we're at the edge
                    {
                        themap.setTileType(x + v, y + w, Constants.TILE_CORRUPTED_SPACE);
                    }
                    break;

                case COR_EDGEADD:
                    if (roomsizex - v == 0 || roomsizey - w == 0 || w == -roomsizex || v == -roomsizey) //we're at the edge
                    {
                        chainfactor = corruptionpercent;
                        while (chainfactor > 0) {
                            //add a tile next to this one
                            xplus += (generator.nextInt(2) == 1 ? -1 : 1);
                            yplus += (generator.nextInt(2) == 1 ? -1 : 1);
                            themap.setTileType(x + v + xplus, y + w + yplus, Constants.TILE_CORRUPTED_FLOOR);
                            chainfactor -= 5;
                        }
                    }
                    break;
            }

        }
    }

    public void makeRandomMapFromSeed(long seed, byte ctype, byte cpercent, short xsize, short ysize) {

        generator.setSeed(seed);
        corruptiontype = ctype;
        corruptionpercent = cpercent;
        themap = new Map(xsize, ysize);
        rooms.removeAllElements();
        numrooms = generator.nextInt(MAXROOMS - 4) + 4; //at least 3 rooms
        roomsizeTotal = (short) ((20 - numrooms + generator.nextInt(10)) / 2); //yay magic numbers

        for (int i = 0; i <= numrooms; i++) {
            int thisroomsize = (short) (roomsizeTotal + generator.nextInt(roomsizeTotal) - generator.nextInt(roomsizeTotal - 1));

            roomsizey = (generator.nextInt(thisroomsize));
            roomsizex = (thisroomsize - roomsizey);

            //all rooms must be at least 3x3
            if (roomsizey <= 2) {
                roomsizey = 3;
            }
            if (roomsizex <= 2) {
                roomsizex = 3;
            }
            x = generator.nextInt(xsize - (roomsizex * 2)) + roomsizex; //dont make rooms that get clipped by the map edges
            y = generator.nextInt(ysize - (roomsizey * 2)) + roomsizey;

            themap.setTileType(x, y, Constants.TILE_FLOOR);
            rooms.addElement(new Point2d(x, y));
            for (v = -roomsizex; v <= roomsizex; v++) {
                for (w = -roomsizey; w <= roomsizey; w++) {
                    //set a tile
                    themap.setTileType(x + v, y + w, Constants.TILE_FLOOR);

                //make some foo monsters to chase the hero
            
            
                }
            }
                /*Monster foo;

            Vector inventory = new Vector();
            inventory.addElement(new ActiveApp(Constants.APP_DEBUGSHOTGUN));

            Image fooImage = Gamestate.resourceManager.getResourceByName("Temp.gif");
            foo = new Monster(new Sprite(fooImage, 16, 16), 10, 20);
            foo.setName("Temp("+w+")");
            foo.setSpriteFileName("Temp.gif");
            foo.setTilePosition(x+generator.nextInt(4)-2,y+generator.nextInt(4)-2);
            Gamestate.gameManager.addNewActor(foo);
            themap.setActorOnTile(foo, foo.getTilePosition().x, foo.getTilePosition().y);
            foo.setInventory(inventory);*/
                
                
                if(generator.nextInt(3) == 0)
                {
                    Vector bombInventory = new Vector();
                    bombInventory.addElement(new ActiveApp(Constants.APP_SELFDESTRUCT));
                    Image bombImage = Gamestate.resourceManager.getResourceByName("SmartBomb.gif");
                    Monster smartBomb = new Monster(new Sprite(bombImage, 16, 16), 10, 20);
                    smartBomb.setName("Smart Bomb");
                    smartBomb.setSpriteFileName("SmartBomb.gif");
                    smartBomb.setTilePosition(x+generator.nextInt(4)-2,y+generator.nextInt(4)-2);
                    Gamestate.gameManager.addNewActor(smartBomb);
                    themap.setActorOnTile(smartBomb, smartBomb.getTilePosition().x, smartBomb.getTilePosition().y);
                    smartBomb.setInventory(bombInventory);
                }
        }


        Point2d goalroom = (Point2d) rooms.elementAt(0);

        for (int i = 0; i < rooms.size(); i++) {

            Point2d currentroom = (Point2d) rooms.elementAt(i);
            while (true) {
                if (!themap.isThereAPath(currentroom, goalroom)) {
                    Point2d randomroom = (Point2d) rooms.elementAt(generator.nextInt(rooms.size()));
                    makePathBetweenRooms(false, currentroom, randomroom);
                }
                else {
                    break;
                }
            }
        }
        Point2d startroom = (Point2d) rooms.elementAt(1);


        int numextrarooms = generator.nextInt(NUM_PATHS_TO_RANDOM_ROOM) + 1;
        for (int z = 0; z < numextrarooms; z++) {
            makePathBetweenRooms(true, (Point2d) rooms.elementAt(generator.nextInt(rooms.size())), (Point2d) rooms.elementAt(generator.nextInt(rooms.size())));
        }

        themap.setTileType(startroom.x, startroom.y, Constants.TILE_PLAYER_START);
        themap.setTileType(goalroom.x, goalroom.y, Constants.TILE_PLAYER_GOAL);




    }

    public Map getFinishedMap() {
        return themap;
    }
}
